<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * 正则表达式很关键的一点，匹配开始永远是从左往右进行匹配，如果这一次匹配，在一开头的位置就匹配到了，就不会往后去匹配了，
    * 只有既设置了全局匹配，又再次进行新的匹配，才会从刚刚的匹配位置开始继续进行新的匹配
    *
    * 量词：描述前面的正则表达式出现的次数
    *   /正则表达式的描述{出现的次数}/
    *
    *   贪婪模式：如果在量词中写出了范围，它会尽可能多地匹配内容
    *   非贪婪模式：尽可能少地匹配内容，只需要在量词后面加上一个问号 ?
    *
    *   /a{2}/ //匹配a连续出现两次
    *   /a{2,5}/ //匹配a连续出现2到5次都可以
    *   /a{0,5}/ //匹配a连续出现0到5次都可以
    *   /./ //匹配任意一个字符，注意只是匹配一个
    *   /a{0,}/ //匹配a连续出现0次及以上 其中{0,}可以简写成* 直接加在a后面
    *   /a{1,}/ //匹配a连续出现1次及以上 其中{1,}可以简写成+ 直接加在a后面
    *   /a{0,1}/ //要么有（匹配一次）要么没有 其中{0,1}可以简写成? 直接加在a后面
    *   /a??/ //两个问号含义不同 前一个问号是两次，后一个问号是非贪婪，匹配a连续出现0次或1次，非贪婪模式，首次全局匹配，如果有0次就不会匹配1次
    *   /a{a,}/ //匹配a连续出现至少a次及以上
    *
    * */
    let reg = /a{5}/ //匹配出现的5个连续的a
    let reg57 = /a{5,7}/ //匹配a连续出现5到7次
    let str = "aaa1aaa2aaa3aaaa4aaaaaaa8aa"

    let reg0 = /a{0,5}/ //匹配a连续出现0次到5次 最不济的情况就是匹配空字符串 ""
    let strb = "bsdcxs"

    console.log(reg.exec(str))
    console.log(reg57.exec(str))
    console.log(reg0.exec(strb))

    /*
    * 如果就要匹配刚好5个a
    * 多一个不行，返回false，少一个也不行，也要返回false，刚好5个a返回true，怎么写?组合着写
    *
    * */
    let reg1 = /[^a]a{5}[^a]/ //前面一个字符不能是a，中间五个必须连续是a，后面一个不能是a

    let str1 = "cccaaaaabnm"

    console.log(reg1.exec(str1))

    /*
    * /a{a,}/
    * */
    let strba = "babb"

    let rega0 = /a{0,}/g //最不济的情况就是匹配连续出现0次a 即空"" 匹配模式全局匹配

    console.log(rega0.exec(strba))
    /*
    * 第一次匹配，正则表达式rega0匹配连续出现0次及以上a，在字符串strba中从左往右开始匹配，"babb"中刚好开头b的左边就是0次a，匹配成功，
    * 返回匹配结果[0:"",index:0,input:"babb",groups:undefined],这次就不会再往后匹配了。因为是全局匹配，所以会记录下这次匹配位置
    * */

    // /ca?/ 匹配内容前面是c后面的a可有可没有
    let strca = "cad"
    let strc = "cd"

    let regca = /ca?/ //匹配内容前面是c后面的a可有可没有
    console.log(regca.exec(strca)) //返回[0: "ca",index: 0,input: "cad",groups: undefined,length: 1]
    console.log(regca.exec(strc)) //返回[0: "c",index: 0,input: "cd",groups: undefined,length: 1]

    //如果正则表达式需要去匹配div标签该怎么写
    let strdiv = "<div>asdfghj</div>"
    let regdiv = /<div.*<\/div>/ //匹配描述是匹配<div></div>,两个div中间有任意一个字符，并且这任意一个字符连续出现0次及以上，
    // 这样不管你要匹配的div标签中有没有内容，有多少内容，都能匹配到这个div标签，因为最不济的匹配结果连续出现0次，就是没有这任意一个字符
    console.log(regdiv.exec(strdiv))

    //但是以上写法有个问题，贪婪模式的问题
    let strdiv1 = "<div>div1</div><div>div2</div>"
    let regdiv1 = /<div>.*<\/div>/g //匹配描述是匹配<div></div>,两个div中间有任意一个字符，并且这任意一个字符连续出现0次及以上，全局匹配
    console.log(regdiv1.exec(strdiv1))
    console.log(regdiv1.exec(strdiv1))
    //第一次匹配会匹配到并且返回第一个div标签，记录位置吗？
    //第二次匹配会匹配到并且返回第二个div标签，记录位置吗？
    //因为贪婪模式的存在，第一次匹配的时候，会把字符串"<div>div1</div><div>div2</div>"中除了最开头的<div>和最末尾的</div>匹配到，
    //中间的div1</div><div>div2这些内容，都会被当做其他任意一个字符连续出现0次及以上，所以两次匹配的结果并不是我们想要的结果
    //要解决这个问题，只需要在量词后面加上一个问号?使其变成非贪婪模式的匹配就行，看下面的代码
    // let regdiv1 = /<div>.*?<\/div>/g 就是在前面这行代码的量词*后面加个? (*是量词，表示连续出现0次及以上，所以给它加问号)

    /*
    * ()把若干个字符分组打包到一起来匹配的意思
    *   括号会捕获匹配到的括号里面的内容
    * 正则表达式可以参与到
    *   match 匹配
    *   match是字符串的方法：从字符串中匹配传入的内容
    *
    *   replace 替换
    *   替换操作接收两个参数：
    *   1.匹配内容
    *   2.替换值
    *
    *   的操作中
    *
    * */
    //比如要匹配"银时"连续出现5次
    let strys = "银时银时银时银时银时"
    let regy = /银时{5}/ //这个方法匹配的是"银时时时时时"，即银后面的时连续出现5次，想要达到效果，就要整体打包匹配
    let regys = /(银时){5}/ //这个才是匹配"银时"连续出现5次
    console.log(regy.exec(strys))
    console.log(regys.exec(strys))

    //假如我们要匹配字符串中的2020，但是我们的现实时间可能不是2020，所以要这么写
    let str20 = "2020-7-21"

    console.log(str20.match(/\d{4}/))

    //如果要匹配里面的数字可以下面这样写
    console.log(str20.match(/\d{1,4}/g)) //全局匹配

    //将连续出现的数字替换成问号隐藏
    console.log(str20.replace(/\d+/g,"??")) //全局匹配替换

    //之前封装replaceAll用了很多代码，现在用正则表达式来试试
    function replaceAll(str,key,value){ //原字符串 key是原字符串中需要被替换的内容 value是替换之后的新内容
        let reg = new RegExp(key,"g") //生成一个正则表达式，传入需要被替换的内容的格式，全局匹配该格式
        return str.replace(reg,value) //传入的字符串使用replace方法，将正则表达式的替换规则传入，将替换值传入，返回replace操作的返回值
    }
    let yszs = "银时真帅银时真帅银时真帅"
    console.log(replaceAll(yszs,"银时","长安忆"))


    //刚刚我们在上面提到括号()有打包分组的功能，说完了打包，现在来说分组

    //分组有非命名捕获分组和命名捕获分组
    //先说非命名捕获分组 格式是：(描述) //括号里面直接写分组的描述
    //还是先获取到一个时间
    let time = "2020-10-20"

    //匹配上面时间的年月日
    let regnyr = /(\d+)-(\d+)-(\d+)/ //括号是将内容进行分组，括号内匹配任意数字(\d)连续出现1次(+)及以上

    //使用replace将字符串由原来的年月日格式改成月日年的格式
    //在replace方法中，接收的第二个参数替换值可以使用$1 $2 $3来表示我们在正则表达式中捕获的用()分组的内容，
    //比如这里$1就表示捕获到的2020 $2表示捕获到的10 $3表示捕获到的20
    console.log(time.replace(regnyr,"$2-$3-$1"))
    //这样就能返回改写成月日年的格式了 10-20-2020


    //命名捕获分组 格式是：(?<命名>描述)
    //上面分组括号里面的问号?和尖括号<>都是固定格式，尖括号里面的命名是自己随便取都行，描述是正则表达式分组内容的具体描述格式
    let date = "2020-10-20"
    let regxin = /(?<year>\d+)-(?<month>\d+)-(?<day>\d+)/ //将正则表达式捕获的内容分组命名为year month day
    console.log(date.replace(regxin,"$<month>-$<day>-$<year>"))
    //返回替换之后的格式 10-20-2020

    //回到exec方法看看
    console.log(regxin.exec(date))
    //[0: "2020-10-20",1: "2020",2: "10",3: "20",index: 0,input: "2020-10-20",groups:{year: "2020",month: "10",day: "20"},length: 4]






</script>
</body>
</html>